import Koa, { Context, Next } from "koa";
import KoaBody from "koa-body";
import KoaRouter from "koa-router";
import { bootstrapControllers } from "koa-ts-controllers";
import path from "path";
import configs from "./configs/index";
import Boom from "@hapi/Boom";
import { Sequelize } from "sequelize-typescript";
import jwt from "jsonwebtoken";
import KoaStaticCache from "koa-static-cache";

//  koa-bodyparser 用来处理post过来的数据

(async () => {
  const app = new Koa();
  const router = new KoaRouter();

  /**
   *  静态资源代理
   *
   */
  app.use(
    KoaStaticCache({
      dir: configs.storage.dir,
      prefix: configs.storage.prefix,
      gzip: true,
      dynamic: true,
    })
  );

  /**
   *  连接数据库
   */
  const db = new Sequelize({
    ...configs.database,
    models: [__dirname + "/models/**/*"],
  });
  try {
    await db.authenticate();
    console.log("成功连接数据库...");
  } catch (e) {
    console.error("连接数据库失败: ", e);
  }

  /**
   *  鉴权
   */
  app.use(async (ctx: Context, next: Next) => {
    let token = ctx.headers["authorization"];

    interface UserInfo {
      id: number;
      name: string;
    }

    if (token) {
      //  为了让ctx.userInfo有类型控制, 在src/types下创建了相关的类型声明文件
      ctx.userInfo = <UserInfo>jwt.verify(token, configs.jwt.privateKey);
    }
    await next();
  });

  /**
   *  注册路由
   *
   *  统一错误处理函数捕获错误
   */
  await bootstrapControllers(app, {
    router,
    basePath: "/api",
    versions: [1],
    controllers: [path.resolve(__dirname, "controllers/**/*.ts")],
    errorHandler: async (err: any, ctx: Context) => {
      interface body {
        statusCode: number;
        error: string;
        message: string;
        errorDetails?: [];
      }

      //  下面这种是服务器自己有逻辑/语法错误
      let status = 500;
      let body: body = {
        statusCode: 500,
        error: "Internal Server error",
        message: "An internal server error occurred",
      };

      //  下面这种是不符合class-validator的错误
      // error = {
      //   data: [{field: string, violations: [object]}],
      //   isBoom: boolean,
      //   isServer: boolean,
      //   output: {
      //     statusCode: number,
      //     payload: {
      //        statusCode: number,
      //        error: string,
      //        message: string
      //     }
      //   }
      // }
      if (err.output) {
        status = err.output.statusCode;
        let { statusCode, error, message } = err.output.payload;
        body = {
          statusCode,
          error,
          message,
        };
        if (err.data) {
          body.errorDetails = err.data;
        }
      }

      ctx.status = status;
      ctx.body = body;
    },
  });

  //  当url 与 routes都不匹配，就执行下面代码
  router.all("/(.*)", async (ctx) => {
    throw Boom.notFound("页面不存在");
  });

  app.use(
    KoaBody({
      multipart: true,
      formidable: {
        uploadDir: configs.storage.dir,
        keepExtensions: true,
      },
    })
  );

  app.use(router.routes());

  //  启动服务，默认端口为localhost:8080
  app.listen(configs.server.port, configs.server.host, () => {
    console.log(
      `服务启动成功 http://${configs.server.host}:${configs.server.port}`
    );
  });
})();
